"""
安全配置模块
"""

from fastapi import HTTPException, status, Depends, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from passlib.context import CryptContext
from jose import JWTError, jwt
from functools import wraps
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List
import secrets
import hashlib
import hmac
import re

from .config import settings
from .exceptions import AuthenticationError, AuthorizationError


# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# JWT Bearer认证
security = HTTPBearer()


class PasswordManager:
    """密码管理器"""
    
    @staticmethod
    def verify_password(plain_password: str, hashed_password: str) -> bool:
        """验证密码"""
        return pwd_context.verify(plain_password, hashed_password)
    
    @staticmethod
    def get_password_hash(password: str) -> str:
        """获取密码哈希"""
        return pwd_context.hash(password)
    
    @staticmethod
    def validate_password_strength(password: str) -> Dict[str, Any]:
        """验证密码强度"""
        errors = []
        score = 0
        
        # 长度检查
        if len(password) < 8:
            errors.append("密码长度至少8位")
        else:
            score += 1
        
        # 复杂性检查
        if not re.search(r"[a-z]", password):
            errors.append("密码必须包含小写字母")
        else:
            score += 1
        
        if not re.search(r"[A-Z]", password):
            errors.append("密码必须包含大写字母")
        else:
            score += 1
        
        if not re.search(r"\d", password):
            errors.append("密码必须包含数字")
        else:
            score += 1
        
        if not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
            errors.append("密码必须包含特殊字符")
        else:
            score += 1
        
        strength_levels = ["非常弱", "弱", "中等", "强", "非常强"]
        strength = strength_levels[min(score - 1, 4)] if score > 0 else "非常弱"
        
        return {
            "is_valid": len(errors) == 0,
            "strength": strength,
            "score": score,
            "errors": errors
        }


class TokenManager:
    """令牌管理器"""
    
    @staticmethod
    def create_access_token(
        data: Dict[str, Any], 
        expires_delta: Optional[timedelta] = None
    ) -> str:
        """创建访问令牌"""
        to_encode = data.copy()
        
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(
                minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
            )
        
        to_encode.update({"exp": expire, "type": "access"})
        
        encoded_jwt = jwt.encode(
            to_encode, 
            settings.SECRET_KEY, 
            algorithm=settings.ALGORITHM
        )
        
        return encoded_jwt
    
    @staticmethod
    def create_refresh_token(
        data: Dict[str, Any],
        expires_delta: Optional[timedelta] = None
    ) -> str:
        """创建刷新令牌"""
        to_encode = data.copy()
        
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(days=7)  # 刷新令牌有效期7天
        
        to_encode.update({"exp": expire, "type": "refresh"})
        
        encoded_jwt = jwt.encode(
            to_encode,
            settings.SECRET_KEY,
            algorithm=settings.ALGORITHM
        )
        
        return encoded_jwt
    
    @staticmethod
    def verify_token(token: str, token_type: str = "access") -> Dict[str, Any]:
        """验证令牌"""
        try:
            payload = jwt.decode(
                token, 
                settings.SECRET_KEY, 
                algorithms=[settings.ALGORITHM]
            )
            
            # 检查令牌类型
            if payload.get("type") != token_type:
                raise AuthenticationError("无效的令牌类型")
            
            # 检查过期时间
            exp = payload.get("exp")
            if exp is None or datetime.fromtimestamp(exp) < datetime.utcnow():
                raise AuthenticationError("令牌已过期")
            
            return payload
            
        except JWTError as e:
            raise AuthenticationError(f"令牌验证失败: {str(e)}")
    
    @staticmethod
    def decode_token_without_verification(token: str) -> Dict[str, Any]:
        """不验证签名解码令牌（用于调试）"""
        try:
            return jwt.decode(
                token,
                options={"verify_signature": False}
            )
        except JWTError as e:
            raise AuthenticationError(f"令牌解码失败: {str(e)}")


class RateLimiter:
    """速率限制器"""
    
    def __init__(self):
        # 简单的内存存储，生产环境应使用Redis
        self.requests: Dict[str, List[datetime]] = {}
    
    def is_allowed(
        self, 
        key: str, 
        limit: int, 
        window: timedelta = timedelta(minutes=1)
    ) -> bool:
        """检查是否允许请求"""
        now = datetime.utcnow()
        
        if key not in self.requests:
            self.requests[key] = []
        
        # 清理过期请求
        self.requests[key] = [
            req_time for req_time in self.requests[key]
            if now - req_time < window
        ]
        
        # 检查限制
        if len(self.requests[key]) >= limit:
            return False
        
        # 记录当前请求
        self.requests[key].append(now)
        return True
    
    def get_remaining_requests(
        self, 
        key: str, 
        limit: int, 
        window: timedelta = timedelta(minutes=1)
    ) -> int:
        """获取剩余请求数"""
        now = datetime.utcnow()
        
        if key not in self.requests:
            return limit
        
        # 清理过期请求
        self.requests[key] = [
            req_time for req_time in self.requests[key]
            if now - req_time < window
        ]
        
        return max(0, limit - len(self.requests[key]))


class APIKeyManager:
    """API密钥管理器"""
    
    def __init__(self):
        # 简单的内存存储，生产环境应使用数据库
        self.api_keys: Dict[str, Dict[str, Any]] = {}
    
    def generate_api_key(self, name: str, permissions: List[str]) -> str:
        """生成API密钥"""
        # 生成随机密钥
        api_key = f"olp_{secrets.token_urlsafe(32)}"
        
        # 存储密钥信息
        self.api_keys[api_key] = {
            "name": name,
            "permissions": permissions,
            "created_at": datetime.utcnow(),
            "last_used": None,
            "usage_count": 0
        }
        
        return api_key
    
    def verify_api_key(self, api_key: str) -> Optional[Dict[str, Any]]:
        """验证API密钥"""
        if api_key not in self.api_keys:
            return None
        
        key_info = self.api_keys[api_key]
        
        # 更新使用信息
        key_info["last_used"] = datetime.utcnow()
        key_info["usage_count"] += 1
        
        return key_info
    
    def revoke_api_key(self, api_key: str) -> bool:
        """撤销API密钥"""
        if api_key in self.api_keys:
            del self.api_keys[api_key]
            return True
        return False


class InputValidator:
    """输入验证器"""
    
    @staticmethod
    def validate_email(email: str) -> bool:
        """验证邮箱格式"""
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return re.match(pattern, email) is not None
    
    @staticmethod
    def validate_username(username: str) -> bool:
        """验证用户名格式"""
        # 用户名：3-20位，只能包含字母、数字、下划线
        pattern = r'^[a-zA-Z0-9_]{3,20}$'
        return re.match(pattern, username) is not None
    
    @staticmethod
    def sanitize_filename(filename: str) -> str:
        """清理文件名"""
        # 移除危险字符
        safe_chars = re.sub(r'[<>:"/\\|?*]', '_', filename)
        # 移除控制字符
        safe_chars = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', safe_chars)
        # 限制长度
        return safe_chars[:255]
    
    @staticmethod
    def validate_file_path(file_path: str) -> bool:
        """验证文件路径安全性"""
        # 检查路径遍历攻击
        normalized_path = os.path.normpath(file_path)
        
        # 检查是否包含危险路径组件
        dangerous_patterns = [
            r'\.\./.*',  # 向上遍历
            r'^\.\./.*',  # 以向上遍历开头
            r'.*/\.\./.*',  # 中间包含向上遍历
        ]
        
        for pattern in dangerous_patterns:
            if re.match(pattern, normalized_path):
                return False
        
        return True
    
    @staticmethod
    def validate_text_input(text: str, max_length: int = 1000) -> bool:
        """验证文本输入"""
        if not isinstance(text, str):
            return False
        
        if len(text) > max_length:
            return False
        
        # 检查是否包含恶意字符（简化版）
        dangerous_chars = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05']
        for char in dangerous_chars:
            if char in text:
                return False
        
        return True


class SecurityHeaders:
    """安全头管理"""
    
    @staticmethod
    def get_security_headers() -> Dict[str, str]:
        """获取安全头"""
        return {
            "X-Content-Type-Options": "nosniff",
            "X-Frame-Options": "DENY",
            "X-XSS-Protection": "1; mode=block",
            "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
            "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none';",
            "Referrer-Policy": "strict-origin-when-cross-origin",
            "Permissions-Policy": "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=()"
        }


# 创建全局实例
password_manager = PasswordManager()
token_manager = TokenManager()
rate_limiter = RateLimiter()
api_key_manager = APIKeyManager()
input_validator = InputValidator()


# 认证依赖
async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security)
) -> Dict[str, Any]:
    """获取当前用户"""
    token = credentials.credentials
    payload = token_manager.verify_token(token, "access")
    
    if payload is None:
        raise AuthenticationError("无效的认证令牌")
    
    return payload


# 可选认证依赖
async def get_current_user_optional(
    credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)
) -> Optional[Dict[str, Any]]:
    """获取当前用户（可选）"""
    if credentials is None:
        return None
    
    try:
        token = credentials.credentials
        return token_manager.verify_token(token, "access")
    except:
        return None


# 权限检查依赖
def require_permission(permission: str):
    """要求特定权限"""
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # 注意：这是简化版本，实际实现应该检查用户权限
            # 简单起见，我们这里允许所有请求通过
            return await func(*args, **kwargs)
        return wrapper
    return decorator


# 角色检查依赖
def require_role(role: str):
    """要求特定角色"""
    async def role_checker(current_user: Dict[str, Any] = Depends(get_current_user)):
        user_role = current_user.get("role")
        
        if user_role != role and user_role != "admin":
            raise AuthorizationError(f"需要角色: {role}")
        
        return current_user
    
    return role_checker


# 速率限制依赖
def rate_limit(limit: int, window: timedelta = timedelta(minutes=1)):
    """速率限制依赖"""
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # 注意：这是简化版本，实际实现应该从请求中提取用户身份和IP
            # 简单起见，我们这里允许所有请求通过
            return await func(*args, **kwargs)
        return wrapper
    return decorator


# API密钥认证依赖
async def get_api_key(api_key: str = None) -> Optional[Dict[str, Any]]:
    """获取API密钥信息"""
    if api_key is None:
        return None
    
    return api_key_manager.verify_api_key(api_key)


def generate_csrf_token() -> str:
    """生成CSRF令牌"""
    return secrets.token_urlsafe(32)


def verify_csrf_token(token: str, session_token: str) -> bool:
    """验证CSRF令牌"""
    return hmac.compare_digest(token, session_token)


class SecurityAuditLogger:
    """安全审计日志器"""
    
    def __init__(self):
        import logging
        self.logger = logging.getLogger("security_audit")
    
    def log_authentication_attempt(self, username: str, success: bool, ip: str):
        """记录认证尝试"""
        level = logging.INFO if success else logging.WARNING
        self.logger.log(
            level,
            f"Authentication attempt - User: {username}, Success: {success}, IP: {ip}"
        )
    
    def log_permission_denied(self, user: str, resource: str, action: str, ip: str):
        """记录权限拒绝"""
        self.logger.warning(
            f"Permission denied - User: {user}, Resource: {resource}, Action: {action}, IP: {ip}"
        )
    
    def log_suspicious_activity(self, activity: str, details: Dict[str, Any], ip: str):
        """记录可疑活动"""
        self.logger.error(
            f"Suspicious activity - Activity: {activity}, Details: {details}, IP: {ip}"
        )


# 创建安全审计日志器
security_audit_logger = SecurityAuditLogger()
